﻿module		core.hgecnfont2;

private import core.hgeall;

private import std.string;
private import std.stream;
private import std.stdio;
private import std.regexp;
private import std.windows.charset;
private import std.utf;


class hgeFontCN2 {
public:
    static const  uint[32] mask= [1,1<<1, 1<<2, 1<<3, 1<<4, 1<< 5, 1<<6, 1<<7,
                                  1<<8, 1<<9, 1<<10, 1<<11, 1<< 12, 1<<13, 1<<14,1<<15,
                                  1<<16, 1<<17, 1<<18, 1<<19, 1<< 20, 1<<21, 1<<22,1<<23,
                                  1<<24, 1<<25, 1<<26, 1<<27, 1<< 28, 1<<29, 1<<30,1<<31
                                 ];


    this( char[] filename)							//根据字体文件创建
    {
        if (filename in fnts) {
            this= fnts[filename];
            return;
        }
        m_name= filename;

        // 必须先初始化 数组
        fb= new  fontBody[65536];

        mes("		------读取中文字体信息开始-----");
        int		tex_width;		//纹理宽度

        float	texx;			//纹理 X
        float	texy;			//纹理 Y


        if (!hge)	hge=gameInfo.hge();

        fScale=1.0f;
        fRot=0.0f;
        fTracking=0.0f;
        hTexture=0;
        fZ=0.5f;
        nBlend=BLEND_COLORMUL | BLEND_ALPHABLEND | BLEND_NOZWRITE;
        dwCol=0xFFFFFFFF;


        if (! std.file.exists(filename))
            throw new Exception("		载入字体文件失败!不存在此文件!	名称=	"~filename);
        if (std.file.getSize(filename) < 32 )
            throw new Exception("		载入字体文件失败!尺寸不符合!		名称=	"~filename);



//////////////////////////////开始读取 ///////////////////////////////

        mes(filename);

        uint    n_font;

        auto mfile = new BufferedFile(filename);



        mfile.read(font_w);		     // 字体点阵宽度
        mfile.read(n_font);		    //  字模数量

        // 获得字符宽度
        char_width 	= font_w;
        fHeight 	= font_w;
        font_w2		= font_w * font_w;
        if (font_w2 %32==0)
            font_int_bit= font_w2/32;
        else
            font_int_bit= font_w2/32 + 1;

        texx=texy=0.0f;
        letter = new hgeSprite(0, 0, 0,FONT_MAP_WIDTH, FONT_MAP_HEIGHT);

        wchar[]	tmpFont= new wchar[n_font];             // 读入 字符文本
        mes("字模数量=",n_font,"字模宽度==",font_w);

        for (int ii=0;ii<n_font; ii++)		//读入所有字符
        {
            mfile.read(tmpFont[ii]);
        }



        fbits = new ubyte[ n_font* font_w * font_w /8];

        int n=0,r=0;
        while (! mfile.eof()) {
            mfile.read(fbits[n]);
            if (fbits[n])
                r++;

            n++;
        }

        if (fbits.length %4 !=0) {
            mes("字模字节数不为4整数倍! 将自己调整长度", fbits.length);
            fbits.length = fbits.length + (fbits.length % 4);
            mes("已调整为",fbits.length);
        }


        mes("读入字模结束,共有bit位== ",fbits.length,"有效位==",r);

        foreach(j, w;	tmpFont) {
            fb[w].beUse = 1;                            // 此字被使用
            fb[w].pos   = j * font_w * font_w;          // 此字的字模偏移量 ,位于 fbits 中

            if (w>= ASCII_FIX && w <= ASCII_END)	//判断字符宽度, 中文12位,英文8位
            {
                fb[w].width= ASCII_WIDTH;
            } else {
                fb[w].width= font_w;
            }

        }

        delete mfile;
        delete tmpFont;

        fnts[filename] = this;
        mes("		------读取中文字体信息完毕-----");
    }

    ~this() {
        delete letter;
        fnts.remove(m_name);
    }

    static void releaseAll() {
        foreach( f; fnts) {
            delete f;
        }
    }
    static void vmes( ...) {
        vmf.length=vmf.length+1;
        void putc(dchar c) {
            std.utf.encode(vmf[$-1], c);
        }
        std.format.doFormat(&putc, _arguments, _argptr);
    }

    void	RenderVmf() {
        uint h= gameInfo.height-60	;		// 初始位置为屏幕底边往上60 像素

        foreach(i,wchar[] a; vmf) {
            Render(0,h-i*fHeight,HGETEXT_LEFT,a);
        }
        vmf.length=0;
    }

    void	Render(float x, float y, int fontAlign, wchar[] string)		//绘制字符串
    {
        float	fx=x;
        fontAlign 	&= HGETEXT_HORZMASK;
        if (fontAlign==HGETEXT_RIGHT) 	fx-=GetStringWidth(string);
        if (fontAlign==HGETEXT_CENTER) 	fx-=cast(int)(GetStringWidth(string)/2.0f);

        wchar	 tmpch;
        wchar	 tmpSpace= cast(wchar)' ';	// Unicode16 字符 空格

        drawBegin();		// 批量画点开始
        foreach(j, sz;	string) {

            if (sz=='\n') {	                // 遇到回车
                y+=fHeight*fScale;
                fx=x;
                if (fontAlign==HGETEXT_RIGHT) fx-=GetStringWidth(string);
                if (fontAlign==HGETEXT_CENTER)fx-=cast(int)(GetStringWidth(string)/2.0f);
            } else if ( sz== tmpSpace) {     //如果是空格, 只增加距离
                fx+=(ASCII_WIDTH + fTracking)*fScale;
            } else if (fb[sz].beUse)		//存在此字
            {
                //letter.SetTextureRect(fb[sz].tx, fb[sz].ty, fb[sz].tw, fHeight);
                //letter.RenderEx(fx, y, fRot, fScale);
                drawFont(fb[sz].pos, cast(int)fx, cast(int)y,fScale);	//画出字符, 注意 fb[sz].pos 指的是字模的位置
                fx+=(fb[sz].width + fTracking)*fScale;
            } else					// 不存在的字符
            {
                tmpch= cast(wchar)'?';

                if (fb[tmpch].beUse) {
                    //letter.SetTextureRect(fb[tmpch].tx, fb[tmpch].ty, fb[sz].tw, fHeight);
                    //letter.RenderEx(fx, y, fRot, fScale);
                    drawFont(fb[tmpch].pos, cast(int)fx, cast(int)y,fScale);
                    fx+=(fb[tmpch].width +fTracking)*fScale;
                }
            }
        }

        drawEnd();		//批量画点结束

    }
//******************************** 使用点列表来画字模 开始 ******************************
    void drawFont2(uint c, int x, int y, float scal=1.0f)		// 在屏幕 x,y 处画一个字模
    {
        int i=0;
        int m=0;
        for (int v=0; v<  font_w  ; v++) {
            for (int u=0 ; u<  font_w  ; u++) {
                if (nPrim >= maxPrim) {
                    drawEnd();
                    drawBegin();
                }
                // int i=nPrim*HGEPRIM_POINT;

                m= c + i;
                if (  fbits[m/8] & mask[m%8]  ) {
                    vb[nPrim].x = u + x;
                    vb[nPrim].y = v + y;
                    vb[nPrim].z = 0.5f;
                    vb[nPrim].col = dwCol;

                    vb[nPrim].tx = 0.0f;
                    vb[nPrim].ty = 0.0f;
                    nPrim++;
                }

                i++;
            }
        }
    }
    // 在屏幕 x,y 处画一个字模, scl是调整字体间距而不是字体大小
    // 此方法与上面方法功能相同,但是用了整数型计算,稍快一些
    void drawFont( uint c, int x, int y, float scl=1.0f) {

        uint 	r1= c / 8;
        uint 	r2= r1 + 20;
        uint[] 	pint= cast(uint[]) fbits[r1..r2];

        uint 	a = 0;
        uint 	b = 0;
        int 	d = 0;
        foreach( m ; pint) {
            for (int n=0;n<32;n++) {
                if (nPrim >= maxPrim) {
                    drawEnd();
                    drawBegin();
                }

                if (m & mask[n] && a+x < gameInfo.width && ( b+y < gameInfo.height)) {

                    vb[nPrim].x = a + x;
                    vb[nPrim].y = b + y;
                    //vb[nPrim].z = 0.5f;
                    vb[nPrim].col = dwCol;
                    //vb[nPrim].tx = 0.0f;
                    //vb[nPrim].ty = 0.0f;
                    nPrim++;
                }
                d++;
                if (d>=font_w2)
                    goto endLoop;

                if (a<11)
                    a++;
                else {
                    a=0;
                    b++;
                }
            }
        }
		
		endLoop:
    }
    void drawBegin() {
        nPrim = 0;
        pvb = hge.Gfx_StartBatch(1,cast(HTEXTURE) 0 ,BLEND_DEFAULT,&maxPrim);     //****** 注意: 这里HGEPRIM_POINT ==1 ,只有改过HGE源码才有效.否则被忽略
        vb  = pvb[0..maxPrim];
        pvb = null;
    }

    void drawEnd() {
        hge.Gfx_FinishBatch(nPrim);
    }
//******************************** 使用点列表来画字模 结束 ******************************

    void printf(float x, float y, int fontAlign, ...) {
        wchar[] line;
        void putc(dchar c) {
            std.utf.encode(line, c);
        }
        std.format.doFormat(&putc, _arguments, _argptr);
        Render(x,y,fontAlign,line);
        delete line;		//必须使用此项,否则游戏开始2分钟后会自动退出
    }

    void SetColor(uint col)									//设置字体颜色
    {
        dwCol=col;
        if (letter)
            letter.SetColor(col);
    }

    void SetZ(float z)										//设置Z缓冲
    {
        fZ=z;
        if (letter)
            letter.SetZ(z);
    }


    void SetBlendMode(int blend)							//设置混和模式
    {
        nBlend=blend;
        if (letter)
            letter.SetBlendMode(blend);

    }


    void SetScale(float scale) 	{
        fScale=scale;
    }				//设置比例
    void SetRotation(float rot) {
        fRot=rot;
    }					//设置旋转角度
    void SetTracking(float tracking) {
        fTracking=tracking;
    }	//设置轨迹

    uint GetColor()  			{
        return dwCol;
    }			//获得颜色
    float GetZ()  				{
        return fZ;
    }				//获得Z缓冲
    int	GetBlendMode()  		{
        return nBlend;
    }			//获得混和模式
    float	GetScale()  			{
        return fScale;
    }			//过得比例
    float	GetRotation()  			{
        return fRot;
    }				//获得旋转角度
    float	GetTracking()  			{
        return fTracking;
    }		//获得轨迹
    float	GetFontHeight()  		{	//获得字体缩放以后的高度
        return fHeight;
    }
    float	GetHeight()  			{	//获得字体高度
        return fHeight*fScale;
    }

    float	GetStringWidth( wchar[] string)					//获得字符串的象素级宽度
    {	//获得字符串的宽度(汉字按两个字节、字母按照一个字节算)
        float w = 0;

        int i=0;
        foreach(ts;	string) {
            if (fb[ts].beUse)
                w += (fb[ts].width + fTracking);
            else if (fb['?'].beUse)
                w += (fb['?'].width + fTracking);
        }

        return w * fScale;
    }


    hgeSprite	GetSprite()						//获得指定的精灵
    {
        return letter;
    }

    this(hgeFontCN2 fn) {
        letter	=	fn.letter;
        fb		=	fn.fb.dup;
        hTexture= 	fn.hTexture;
        fHeight	=	fn.fHeight;
        fScale	=	fn.fScale;
        fRot	=	fn.fRot;
        fTracking=	fn.fTracking;
        dwCol	=	fn.dwCol;
        fZ		=	fn.fZ;
        nBlend	=	fn.nBlend;

        m_name	= 	fn.m_name;
        fbits	= 	fn.fbits;
        maxPrim	=  	fn.maxPrim;
        nPrim	= 	fn.nPrim;
        vb		=	fn.vb;
        pvb		=	fn.pvb;

        font_w	= 	fn.font_w;
        font_w2 =	fn.font_w2;
        font_int_bit= fn.font_int_bit;
    }

private:
    this() {		};
    //根据字体对象创建
    static ifHge	hge;

    hgeSprite		letter;

    struct		fontBody {
        ushort	beUse;		//是否被使用
        ushort  width;      // 字体宽度,主要区分 汉字与英文的宽度不同
        uint    pos;        //在 fbits 中的位置
    }

    int 		font_w;		//字模宽度
    int			font_w2;	//字模面积 , = font_w * font_w
    int			font_int_bit;	//此面积需要几个整数来存放?  font_w2 / 32 ,如有余数则+1


    fontBody[]	fb;
    HTEXTURE	hTexture;
    float		fHeight;
    float		fScale, fRot;
    float		fTracking;

    struct		VmesInfo {
        float	 	x;
        float 		y;
        int   		_align;
        wchar[]	info;
    }

    static wchar[][]		vmf;	// 供其它模块使用的输出暂存器, 最后将此变量一次性输出到屏幕

    uint		dwCol;
    float		fZ;
    int			nBlend;

    char[]		m_name;					//字体文件名
    ubyte[]    fbits;

    int        maxPrim;                // 最大图形数
    int        nPrim;                  // 顶点计数器
    hgeVertex[]  vb;                   // 顶点数组
    hgeVertex*   pvb;                   // 顶点指针

    static	hgeFontCN2[char[]] 		fnts;	//字体数组
};

